import React, { FunctionComponent } from 'react';
import { graphql, useFragment } from 'react-relay';
import { Field, Form, Formik } from 'formik';
import * as Yup from 'yup';
import { FormikConfig } from 'formik/dist/types';
import { GenericContext } from '@components/common/model/GenericContextModel';
import ObjectAssigneeField from '@components/common/form/ObjectAssigneeField';
import TextField from '../../../../components/TextField';
import { SubscriptionFocus } from '../../../../components/Subscription';
import CreatedByField from '../../common/form/CreatedByField';
import { ExternalReferencesValues } from '../../common/form/ExternalReferencesField';
import ObjectMarkingField from '../../common/form/ObjectMarkingField';
import CommitMessage from '../../common/form/CommitMessage';
import { adaptFieldValue } from '../../../../utils/String';
import StatusField from '../../common/form/StatusField';
import { convertAssignees, convertCreatedBy, convertMarkings, convertStatus } from '../../../../utils/edition';
import { isNone, useFormatter } from '../../../../components/i18n';
import { Option } from '../../common/form/ReferenceField';
import { MalwareAnalysisEditionOverview_malwareAnalysis$key as malwareAnalysis$key } from './__generated__/MalwareAnalysisEditionOverview_malwareAnalysis.graphql';
import DateTimePickerField from '../../../../components/DateTimePickerField';
import { fieldSpacingContainerStyle } from '../../../../utils/field';
import OpenVocabField from '../../common/form/OpenVocabField';
import ConfidenceField from '../../common/form/ConfidenceField';
import { useSchemaEditionValidation } from '../../../../utils/hooks/useEntitySettings';
import useFormEditor, { GenericData } from '../../../../utils/hooks/useFormEditor';
import AlertConfidenceForEntity from '../../../../components/AlertConfidenceForEntity';
import { parse } from '../../../../utils/Time';

const malwareAnalysisMutationFieldPatch = graphql`
    mutation MalwareAnalysisEditionOverviewFieldPatchMutation(
        $id: ID!
        $input: [EditInput]!
        $commitMessage: String
        $references: [String]
    ) {
        malwareAnalysisFieldPatch(id: $id, input: $input, commitMessage: $commitMessage, references: $references){
            ...MalwareAnalysisEditionOverview_malwareAnalysis
            ...MalwareAnalysis_malwareAnalysis
        }

    }
`;

export const malwareAnalysisEditionOverviewFocus = graphql`
    mutation MalwareAnalysisEditionOverviewFocusMutation($id: ID!, $input: EditContext!) {
        malwareAnalysisContextPatch(id: $id,  input: $input) {
            id
        }
    }
`;

export const malwareAnalysisMutationRelationAdd = graphql`
    mutation MalwareAnalysisEditionOverviewRelationAddMutation(
        $id: ID!
        $input: StixRefRelationshipAddInput!
    ) {
        malwareAnalysisRelationAdd(id: $id, input: $input) {
            id
            from {
                ...MalwareAnalysisEditionOverview_malwareAnalysis
            }
        }
    }
`;

export const malwareAnalysisMutationRelationDelete = graphql`
    mutation MalwareAnalysisEditionOverviewRelationDeleteMutation(
        $id: ID!
        $toId: StixRef!
        $relationship_type: String!
    ) {
        malwareAnalysisRelationDelete(id: $id, toId: $toId, relationship_type: $relationship_type) {
            ...MalwareAnalysisEditionOverview_malwareAnalysis
        }
    }
`;

export const malwareAnalysisEditionOverviewFragment = graphql`
    fragment MalwareAnalysisEditionOverview_malwareAnalysis on MalwareAnalysis {
        id
        product
        result_name
        version
        submitted
        result
        confidence
        entity_type
        createdBy {
            ... on Identity {
                id
                name
                entity_type
            }
        }
        objectMarking {
            id
            definition_type
            definition
            x_opencti_order
            x_opencti_color
        }
        objectAssignee {
            id
            name
            entity_type
        }
        status {
            id
            order
            template {
                name
                color
            }
        }
        workflowEnabled
    }
`;
interface MalwareAnalysisEditionOverviewProps {
  malwareAnalysisRef: malwareAnalysis$key,
  context?: readonly (GenericContext | null)[] | null;
  enableReferences?: boolean
  handleClose: () => void
}

interface MalwareAnalysisEditionFormValues {
  message?: string
  references: ExternalReferencesValues
  createdBy?: Option
  x_opencti_workflow_id: Option
  objectMarking?: Option[]
  objectAssignee?: Option[],
  submitted?: Option;
}

// eslint-disable-next-line max-len
const MalwareAnalysisEditionOverview: FunctionComponent<MalwareAnalysisEditionOverviewProps> = ({ malwareAnalysisRef, context, enableReferences = false, handleClose }) => {
  const { t_i18n } = useFormatter();
  const basicShape = {
    result_name: Yup.string().required(t_i18n('This field is required')),
    product: Yup.string().required(t_i18n('This field is required')),
    submitted: Yup.date().nullable().typeError(t_i18n('The value must be a datetime (yyyy-MM-dd hh:mm (a|p)m)')),
    confidence: Yup.number(),
    result: Yup.string().nullable(),
    version: Yup.string().nullable(),
    x_opencti_workflow_id: Yup.object().nullable(),
  };
  const malwareAnalysisValidator = useSchemaEditionValidation('Malware-Analysis', basicShape);
  const malwareAnalysis = useFragment(malwareAnalysisEditionOverviewFragment, malwareAnalysisRef);

  const queries = {
    fieldPatch: malwareAnalysisMutationFieldPatch,
    relationAdd: malwareAnalysisMutationRelationAdd,
    relationDelete: malwareAnalysisMutationRelationDelete,
    editionFocus: malwareAnalysisEditionOverviewFocus,
  };
  const editor = useFormEditor(
    malwareAnalysis as GenericData,
    enableReferences,
    queries,
    malwareAnalysisValidator,
  );

  const createdBy = convertCreatedBy(malwareAnalysis);
  const objectMarking = convertMarkings(malwareAnalysis);
  const status = convertStatus(t_i18n, malwareAnalysis);

  const handleSubmitField = (name: string, value: Option[] | string) => {
    if (!enableReferences) {
      malwareAnalysisValidator
        .validateAt(name, { [name]: value })
        .then(() => {
          editor.fieldPatch({
            variables: {
              id: malwareAnalysis.id,
              input: [{ key: name, value: Array.isArray(value) ? value.map((o) => o.value) : [value ?? ''] }],
            },
          });
        })
        .catch(() => false);
    }
  };

  const onSubmit: FormikConfig<MalwareAnalysisEditionFormValues>['onSubmit'] = (values, { setSubmitting }) => {
    const { message, references, ...otherValues } = values;
    const commitMessage = message ?? '';
    const commitReferences = (references ?? []).map(({ value }) => value);

    const inputValues = Object.entries({
      ...otherValues,
      createdBy: values.createdBy?.value,
      x_opencti_workflow_id: values.x_opencti_workflow_id?.value,
      objectMarking: (values.objectMarking ?? []).map(({ value }) => value),
      objectAssignee: (values.objectAssignee ?? []).map(({ value }) => value),
      submitted: values.submitted ? parse(values.submitted).format() : null,
    }).map(([key, value]) => ({ key, value: adaptFieldValue(value) }));

    editor.fieldPatch({
      variables: {
        id: malwareAnalysis.id,
        input: inputValues,
        commitMessage: commitMessage.length > 0 ? commitMessage : null,
        references: commitReferences,
      },
      onCompleted: () => {
        setSubmitting(false);
        handleClose();
      },
    });
  };
  const initialValues = {
    result_name: malwareAnalysis.result_name,
    product: malwareAnalysis.product,
    submitted: !isNone(malwareAnalysis.submitted) ? malwareAnalysis.submitted : null,
    confidence: malwareAnalysis.confidence,
    result: malwareAnalysis.result,
    version: malwareAnalysis.version,
    x_opencti_workflow_id: status as Option,
    createdBy: createdBy as Option,
    objectMarking,
    objectAssignee: convertAssignees(malwareAnalysis),
    references: [],
  };
  return (
    <Formik
      enableReinitialize={true}
      initialValues={initialValues}
      validationSchema={malwareAnalysisValidator}
      onSubmit={onSubmit}
    >
      {({
        submitForm,
        isSubmitting,
        setFieldValue,
        values,
      }) => (
        <Form style={{ margin: '20px 0 20px 0' }}>
          <AlertConfidenceForEntity entity={malwareAnalysis} />
          <Field
            component={TextField}
            name="product"
            label={t_i18n('Product')}
            fullWidth
            onFocus={editor.changeFocus}
            onSubmit={handleSubmitField}
            helperText={
              <SubscriptionFocus context={context} fieldName="product" />
                        }
          />
          <Field
            component={TextField}
            name="result_name"
            label={t_i18n('Report name')}
            fullWidth
            style={{ marginTop: 20 }}
            onFocus={editor.changeFocus}
            onSubmit={handleSubmitField}
            helperText={
              <SubscriptionFocus context={context} fieldName="result_name" />
                        }
          />
          <Field
            component={TextField}
            name="version"
            label={t_i18n('Version of the product')}
            fullWidth
            style={{ marginTop: 20 }}
            onFocus={editor.changeFocus}
            onSubmit={handleSubmitField}
            helperText={
              <SubscriptionFocus context={context} fieldName="version" />
                        }
          />
          <Field
            component={DateTimePickerField}
            name="submitted"
            onFocus={editor.changeFocus}
            onSubmit={handleSubmitField}
            textFieldProps={{
              label: t_i18n('Submission date'),
              variant: 'standard',
              fullWidth: true,
              style: { marginTop: 20 },
              helperText: (
                <SubscriptionFocus context={context} fieldName="submitted"/>
              ),
            }}
          />
          <OpenVocabField
            label={t_i18n('Maliciousness')}
            type="malware-result-ov"
            name="result"
            onSubmit={(name, value) => handleSubmitField(name, value as string)}
            onChange={(name, value) => setFieldValue(name, value)}
            containerStyle={fieldSpacingContainerStyle}
            variant="edit"
            multiple={false}
            editContext={context}
          />
          <ConfidenceField
            entityType="Malware-Analysis"
            onFocus={editor.changeFocus}
            onSubmit={(name, value) => handleSubmitField(name, (value ?? '').toString())}
            containerStyle={fieldSpacingContainerStyle}
            editContext={context}
            variant="edit"
          />
          {malwareAnalysis?.workflowEnabled && (
          <StatusField
            name="x_opencti_workflow_id"
            type="MalwareAnalysis"
            onFocus={editor.changeFocus}
            onChange={handleSubmitField}
            setFieldValue={setFieldValue}
            style={{ marginTop: 20 }}
            helpertext={
              <SubscriptionFocus
                context={context}
                fieldName="x_opencti_workflow_id"
              />
                            }
          />
          )}
          <ObjectAssigneeField
            name="objectAssignee"
            style={fieldSpacingContainerStyle}
            helpertext={
              <SubscriptionFocus context={context} fieldname="objectAssignee" />
            }
            onChange={editor.changeAssignee}
          />
          <CreatedByField
            name="createdBy"
            style={{ marginTop: 20, width: '100%' }}
            setFieldValue={setFieldValue}
            helpertext={
              <SubscriptionFocus context={context} fieldName="createdBy" />
                        }
            onChange={editor.changeCreated}
          />
          <ObjectMarkingField
            name="objectMarking"
            style={{ marginTop: 20, width: '100%' }}
            helpertext={
              <SubscriptionFocus
                context={context}
                fieldname="objectMarking"
              />
                        }
            setFieldValue={setFieldValue}
            onChange={editor.changeMarking}
          />
          {enableReferences && (
          <CommitMessage
            submitForm={submitForm}
            disabled={isSubmitting}
            setFieldValue={setFieldValue}
            values={values.references}
            id={malwareAnalysis.id}
            open={false}
          />
          )}
        </Form>
      )}
    </Formik>
  );
};

export default MalwareAnalysisEditionOverview;
